--窗体里边注册事件 窗口关闭的时候要移除
--self:registerMsg(MsgType.SC_LOGIN ,handler(self,self.receiveHandler));
--self:removeRegister(MsgType.SC_LOGIN ,handler(self,self.receiveHandler));
local ProtoMgr = class("ProtoMgr");
local SOCKET = {LUA_TCP_SOCKET = 0,LUA_WEB_SOCKET = 1};
--local curSocket = SOCKET.LUA_TCP_SOCKET;
local curSocket = SOCKET.LUA_WEB_SOCKET;
local WebNet = require(SCRIPTS_DIR .. ".network.WebNet");
local TcpNet = require(SCRIPTS_DIR .. ".network.TcpNet");
local Packet = require(SCRIPTS_DIR .. ".network.Packet")
local m_isPacketFull = true;
local tmpPacket = nil;
--数据包格式(DATA_LEN字节(存储的是数据长度(cmd+数据)) + CMD_LEN字节(存储的是协议ID) + 数据)
--存储数据长度
local DATA_LEN = 2
--存储协议ID
local CMD_LEN = 2

function ProtoMgr:ctor()
    self.socketLogin = nil
    self.socketGate = nil
    self.socketGame = nil
    
    self.sucessLogin = false;
    self.sucessGate = false;
    self.sucessGame = false;

    self._listenerList = {};
    self.showHint = true;
end

function ProtoMgr:createSocket()
    local socket = nil
    if curSocket == SOCKET.LUA_TCP_SOCKET then
        socket = TcpNet.new();
    elseif curSocket == SOCKET.LUA_WEB_SOCKET then
        socket = WebNet.new();
    end
    return socket
end

function ProtoMgr:connect(host,port,sockettype)
    if curSocket == SOCKET.LUA_WEB_SOCKET and type(port) == "number" then
        -- body
        host = "ws://" .. host .. ":" .. tostring(port)
        port = nil
    end
    sockettype = sockettype or enums.Socket.Login
    if sockettype == enums.Socket.Login then
        if not self.sucessLogin then
            self.socketLogin = self:createSocket()
            self.socketLogin:connectSocket(host,port);
        else
            mgrs.log:printDebug("LoginSocket has connect")
        end
    elseif sockettype == enums.Socket.Game then
        if not self.sucessGame then
            self.socketGame = self:createSocket()
            self.socketGame:connectSocket(host,port);
        else
            mgrs.log:printDebug("GameSocket has connect")
        end
    end
    mgrs.input:lock(enums.Locker.ConnectSocket);
end

function ProtoMgr:close(sockettype)
    sockettype = sockettype or enums.Socket.Login
    if sockettype == enums.Socket.Login then
        self.socketLogin:closeSocket();
        mgrs.log:printDebug("LoginSocket closeSocket")
    elseif sockettype == enums.Socket.Game then
        self.socketGame:closeSocket();
        mgrs.log:printDebug("GameSocket closeSocket")
    end
end

function ProtoMgr:send(data,sockettype)
    sockettype = sockettype or enums.Socket.Login
    if sockettype == enums.Socket.Login then
       if self.sucessLogin then
           self.socketLogin:sendData(data);
       else
           mgrs.log:printDebug("socketLogin is closed"); 
       end
    elseif sockettype == enums.Socket.Game then
        if self.sucessGame then
           self.socketGame:sendData(data);
        else
           mgrs.log:printDebug("socketGame is closed"); 
        end 
    end
    
end

function ProtoMgr:bin2hex(binary)
    local t = {}
    for i = 1, string.len(binary) do
        t[#t + 1] = string.format("0x%02x", string.byte(binary, i))
    end
    return table.concat(t, " ")
end

function ProtoMgr:parseMessage(message)
    mgrs.log:printNotice("receive binary msg: len = %s, binary = %s", string.len(message), self:bin2hex(message));
    local pack = Packet.new();
    pack:pWriteBuf(message);
    self:doNetDatas(pack);
end


function ProtoMgr:dispatchData(buf)
    -- body
    local pack = Packet.new();
    pack:pWriteBuf(buf);
    pack:setPos(1);
    local protoId = pack:pReadProtoId();
    mgrs.log:printDebug("收到 ProtoID = " .. protoId);
    self:receive(protoId,pack);
end

function ProtoMgr:doNetDatas(pack)
    --粘包问题处理
    pack:setPos(1);
    if m_isPacketFull then
        local realLen = pack:getLen() - (DATA_LEN + CMD_LEN);
        if realLen < 0 then
            -- body
            mgrs.log:printError("数据包有问题");
            return;
        end
        local needLen = pack:pReadLength();
        if realLen >= needLen - CMD_LEN then
            -- 足够的包
            local curDataBuf = pack:readBuf(needLen);
            self:dispatchData(curDataBuf);
            --处理剩余数据
            if realLen ~= needLen - CMD_LEN then
                mgrs.log:printDebug("数据有剩余 处理剩余数据");
                local nPack = Packet.new();
                local buff = pack:readBuf(realLen - (needLen - CMD_LEN));
                nPack:writeBuf(buff);
                pack = nil;
                self:doNetDatas(nPack);
            end
        else
            -- 数据不够一条 等待下一条数据
            m_isPacketFull = false;
            tmpPacket = pack;
            mgrs.log:printDebug("半包数据:" .. tmpPacket:toString() .. "等待下一条数据");
        end
    else
        --半包 要组包
        m_isPacketFull = true;
        local nPack = Packet.new();
        nPack:writeBytes(tmpPacket);
        tmpPacket = nil;
        nPack:writeBytes(pack);
        pack = nil;
        mgrs.log:printDebug("组包数据:" .. nPack:toString() .. "  解析开始");
        self:doNetDatas(nPack);
    end
end


--desc:收到数据
--@msgid 协议ID
--@message Packet对象(除去协议ID)

function ProtoMgr:receive(msgid,message)
    -- body
    self:_disPatchProto(msgid,message);
end

function ProtoMgr:socketSucess(socket)
    -- body
    if self.socketLogin == socket then
        self.sucessLogin = true
        mgrs.log:printDebug("LoginsocketSucess");
        mgrs.event:dispatchEvent({name = enums.Event.SocketOpen,data = enums.Socket.Login});
    elseif self.socketGame == socket then
        self.sucessGame = true
        mgrs.log:printDebug("GamesocketSucess");
        mgrs.event:dispatchEvent({name = enums.Event.SocketOpen,data = enums.Socket.Game});
    end
    mgrs.input:unLock(enums.Locker.ConnectSocket);
end

function ProtoMgr:socketError(socket)
    -- body(服务器没有开)
    if self.socketLogin == socket then
        self.sucessLogin = false
        mgrs.log:printDebug("LoginSocket Error");
    elseif self.socketGate == socket then
        self.sucessGate = false
        mgrs.log:printDebug("GateSocket Error");
    elseif self.socketGame == socket then
        self.sucessGame = false
        mgrs.log:printDebug("GameSocket Error");
    end
    mgrs.input:unLock(enums.Locker.ConnectSocket);
    mgrs.hint:showHint("网络异常")
    mgrs.hint:startShowHint();
    mgrs.log:printDebug("socketError");
end

function ProtoMgr:socketExit(socket)
    -- body
    
end

function ProtoMgr:socketClosed(socket)
    -- body
    if self.socketLogin == socket then
        self.sucessLogin = false
        mgrs.log:printDebug("LoginSocket Closed");
        mgrs.event:dispatchEvent({name = enums.Event.SocketClosed,data = enums.Socket.Login});
    elseif elf.socketGame == socket then
        self.sucessGame = false
        mgrs.log:printDebug("GameSocket Closed");
        mgrs.event:dispatchEvent({name = enums.Event.SocketClosed,data = enums.Socket.Game});
    end
    if self.showHint then
        mgrs.hint:showHint("网络断开")
        mgrs.hint:startShowHint();
    end
    self.showHint = true
end

function ProtoMgr:setIsShowHint(show)
    -- body
    self.showHint = show
end


-- 注册消息
-- 注册之后 接受到服务器消息之后进行广播，谁注册，谁响应
function ProtoMgr:registerMsg(msgid,callBack)
    self._listenerList[msgid] = self._listenerList[msgid] or {};
    local isExist = self:_registerCbkIsExit(msgid,callBack);
    if not isExist then
        table.insert(self._listenerList[msgid],callBack);
    else
        mgrs.log:printWarn("%s 已经注册啦",msgid);
    end
end

function ProtoMgr:_registerCbkIsExit( msgid,callBack )
    for k,v in pairs(self._listenerList[msgid]) do
        if v == callBack then
            return true;
        end
    end
    return false;
end

-- 移除注册消息
function ProtoMgr:removeRegister( msgid,callBack )
    if self._listenerList[msgid] then
        for k,v in pairs(self._listenerList[msgid]) do
            if v == callBack then
                table.remove(self._listenerList[msgid],k);
                break;
            end
        end
    end
end
-- 移除所有注册消息
function ProtoMgr:removeAllMsg()
    self._listenerList = nil;
    self._listenerList = {};
end

-- 接受消息
-- 派发事件
function ProtoMgr:_disPatchProto(msgid,data)
    if self._listenerList[msgid] and #self._listenerList[msgid] ~= 0 then
        for k,v in pairs(self._listenerList[msgid]) do
            v(data,msgid);
        end
        mgrs.log:printDebug("protoID = %d 解析完成！",msgid);
    else
        mgrs.log:printWarn("protoID = %d 没有被监听！！！！",msgid);
    end
end


mgrs.proto = nil;
mgrs.singleClass(mgrs,ProtoMgr,"proto");